/*
ajax 请求函数模块
*/
import axios from "axios";
import { message } from "antd";
/**
 * 向外部暴露一个函数 ajax
 * @param {*} url 请求路径，默认为空
 * @param {*} data 请求参数，默认为空对象
 * @param {*} type 请求方法，默认为GET
 */
// export default function ajax(url = "", data = {}, type = "GET") {
//   // 返回值 Promise对象 （异步返回的数据是response.data，而不是response）
//   return new Promise(function (resolve, reject) {
//     // （利用axios）异步执行ajax请求
//     let promise; // 这个内部的promise用来保存axios的返回值(promise对象)
//     if (type === "GET") {
//       // 准备 url query 参数数据
//       let dataStr = ""; // 数据拼接字符串，将data连接到url
//       Object.keys(data).forEach((key) => {
//         dataStr += key + "=" + data[key] + "&";
//       });
//       if (dataStr !== "") {
//         dataStr = dataStr.substring(0, dataStr.lastIndexOf("&"));
//         url = url + "?" + dataStr;
//       }
//       // 发送 get 请求
//       promise = axios.get(url);
//     } else {
//       // 发送 post 请求
//       promise = axios.post(url, data);
//     }
//     promise
//       .then((response) => {
//         // 成功回调resolve()
//         resolve(response.data);
//       })
//       .catch((error) => {
//         // 失败回调reject()
//         reject(error);
//       });
//   });
// }
const pendingMap = new Map();
//创建一个loading保存实例
const loadingInstance = {
  _target: null,
  _count: 0,
};
/**
 *
 * @param {*} axiosConfig 请求参数
 * @param {*} customOption 请求配置
 */
export default function ajax(axiosConfig, customOption) {
  // 自定义配置
  let custom_option = Object.assign(
    {
      repeat_request_cancel: true, // 是否开启取消重复请求, 默认为 true
      loading: true, // 是否开启loading层效果, 默认为false
      loading_message: "", // loading文字信息
      error_message_show: true, // 是否开启接口错误信息展示,默认为true
      code_message_show: true, // 是否开启code不为0时的信息提示, 默认为false
      clean_data: true, // 是否开启格式数据,默认为true
    },
    customOption
  );
  // 创建axios实例
  const service = axios.create({
    baseURL: axiosConfig.baseURL ? axiosConfig.baseURL : "",
    timeout: 20000, // 统一的超时时间
  });

  // 请求拦截器
  service.interceptors.request.use(
    (config) => {
      removePending(config);
      custom_option.repeat_request_cancel && addPending(config);
      if (custom_option.loading) {
        loadingInstance._count++;
        if (loadingInstance._count === 1) {
          loadingInstance._target = message.loading("加载中...", 0);
        }
      }
      return config;
    },
    (error) => {
      return Promise.reject(error);
    }
  );

  // 响应拦截器
  service.interceptors.response.use(
    (response) => {
      removePending(response.config);
      custom_option.loading && closeLoading(custom_option);
      const dataAxios = response.data;
      const { code, message: dataMessage } = dataAxios;
      if (!code) {
        return dataAxios;
      } else {
        switch (code) {
          case 200:
            return dataAxios;
          default:
            custom_option.code_message_show && message.error(dataMessage);
            return dataAxios;
        }
      }
    },
    (error) => {
      error.config && removePending(error.config);
      custom_option.loading && closeLoading(custom_option);
      custom_option.error_message_show && httpErrorStatusHandle(error);
      return Promise.reject(error);
    }
  );

  return service(axiosConfig);
}

const addPending = (config) => {
  const pendingKey = getPendingKey(config);
  if (pendingMap.has(pendingKey)) {
    // 如果存在这么一个key，调用纯在的key对应的fun，取消请求
    pendingMap.get(pendingKey)();
    pendingMap.delete(pendingKey);
  } else {
    // 不存在这么一个key，则将cancel函数加入pendingMap
    config.cancelToken = new axios.CancelToken(function executor(cancel) {
      pendingMap.set(pendingKey, cancel);
    });
  }
};

const removePending = (config) => {
  const pendingKey = getPendingKey(config);
  if (pendingMap.has(pendingKey)) {
    // 如果存在这么一个key，调用纯在的key对应的fun，取消请求
    pendingMap.get(pendingKey)(pendingKey);
    pendingMap.delete(pendingKey);
  }
};

const getPendingKey = (config) => {
  let { url, method, params, data } = config;
  if (typeof data === "string") data = JSON.parse(data); // response里的data为字符串对象
  return [url, method, params, JSON.stringify(data)].join("&");
};
/**
 * 处理异常
 * @param {*} error
 */
const httpErrorStatusHandle = (error) => {
  if (axios.isCancel(error))
    return message.info("取消重复的请求" + error.message);
  let messageInfo = "";
  if (error && error.response) {
    switch (error.response.status) {
      case 302:
        messageInfo = "接口重定向";
        break;
      case 400:
        messageInfo = "参数错误";
        break;
      case 401:
        messageInfo = "未登录或登陆超时";
        break;
      case 403:
        messageInfo = "无权限操作";
        break;
      case 404:
        messageInfo = `请求地址出错${error.response.config.url}`;
        break;
      case 408:
        messageInfo = "请求超时";
        break;
      case 409:
        messageInfo = "系统已存在相同数据";
        break;
      case 500:
        messageInfo = "服务器内部错误";
        break;
      case 501:
        messageInfo = "服务器未实现";
        break;
      case 502:
        messageInfo = "网关错误";
        break;
      case 503:
        messageInfo = "服务器不可用";
        break;
      case 504:
        messageInfo = "服务器无法访问，请稍后再试";
        break;
      case 505:
        messageInfo = "http版本不支持";
        break;
      default:
        messageInfo = "异常问题，请联系服务员";
    }
  }
  if (error.message.includes("timeout")) messageInfo = "网络请求超时";
  if (error.message.includes("Network"))
    messageInfo = window.navigator.onLine ? "服务端异常" : "您断网了";
  message.error(messageInfo);
};

const closeLoading = (custom_option) => {
  if (custom_option.loading && loadingInstance._count > 0)
    loadingInstance._count--;
  if (loadingInstance._count === 0) {
    loadingInstance._target();
    loadingInstance._target = null;
  }
};
